use axum::{
    extract::{rejection::JsonRejection, FromRequest, MatchedPath, Request, State},
    http::StatusCode,
    response::{IntoResponse, Response},
    Json,
};
use axum_macros::FromRequest;

use serde_json::json;
use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct AppError(anyhow::Error);

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let body = Json(json!({ "error": self.0.to_string() }));

        (
            StatusCode::INTERNAL_SERVER_ERROR,
            // format!("Something went wrong: {}", self.0),
            body
        )
            .into_response()
    }
}

// This enables using `?` on functions that return `Result<_, anyhow::Error>` to turn them into
// `Result<_, AppError>`. That way you don't need to do that manually.
impl<E> From<E> for AppError
where
    E: Into<anyhow::Error>,
{
    fn from(err: E) -> Self {
        Self(err.into())
    }
}

pub struct MyRejection(Response);

// #[derive(FromRequest)]
// #[from_request(via(axum::Json, rejection(AppError)))]
// pub struct AppJson<T>(T);
#[derive(FromRequest)]
#[from_request(via(axum::Json), rejection(MyRejection))]
pub struct AppJson<T>(pub T);

// impl <T: Serialize> IntoResponse for AppJson<T> {
//     fn into_response(self) -> Response {
//         let body = Json(json!(self.0));

//         (StatusCode::OK, body).into_response()
//     }
// }

impl<T> IntoResponse for AppJson<T>
where
    axum::Json<T>: IntoResponse,
{
    fn into_response(self) -> Response {
        axum::Json(self.0).into_response()
    }
}

impl From<JsonRejection> for MyRejection {
    fn from(j: JsonRejection) -> Self {
        
        Self((j.status(), Json(json!(
            {
                "code": j.status().as_u16(),
                "message": "Json deserialization failed",
                "error": j.body_text()
            })
        )).into_response())
    }
}

impl IntoResponse for MyRejection {
    fn into_response(self) -> Response {
        self.0
    }
}
